home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
EnigmA Amiga Run 1996 June
/
EnigmA AMIGA RUN 08 (1996)(G.R. Edizioni)(IT)[!][issue 1996-06][EARSAN CD VII].iso
/
earcd
/
utilsys
/
updatcpy.lha
/
UpdateCopy
/
Source
/
updatecopy.e
Wrap
Text File
|
1996-04-15
|
20KB
|
639 lines
/* Updatecopy.e
** Copies multiple files/directories to one destination.
** Not existing directories are created.
** Already existing files are only replaced by newer ones
** (updatecopy first checks for versions-string and then
** for dates).
**
** $VER: UpdateCopy.e 0.40 (14.04.96)
**
** This program is Cardware. If you use it you should send an Email to
** the author. Also small presents are very welcome.
** You may use this sourcefile or parts of it freely in your programs.
** But please do not spread a modified version under this name (UpdateCopy).
** For Bugreports, ideas or anything else send a Email to:
** ss37@irz.inf.tu-dresden.de
**
** Sven Steiniger, 1996
**
** Fold-start: ->// ""
** Fold-stop: ->\\
*/
OPT OSVERSION=37
MODULE 'dos/dos','dos/dosasl','dos/dostags',
'tools/file'
RAISE "MEM" IF String()=NIL,
"ADDP" IF AddPart()=DOSFALSE,
"CTRL" IF CtrlC()=TRUE,
"COPY" IF FileLength()=-1,
"MEM" IF AllocDosObject()=NIL
CONST MAXPATH=255, -> Maximum path length
SPACEADD=3, -> Number of spaces per indent
SAFETYBYTES=100, -> Maximum length of versionstring
BIGFILESIZE=100000 -> Files bigger than that are not read
-> completly into memory
CONST PATHLENGTH=MAXPATH-1,
BIGFILEMEM=BIGFILESIZE+SAFETYBYTES
DEF frompath[MAXPATH]:STRING, -> actual sourcepath
fromlist:PTR TO LONG, -> pointer to array of sourcestrings
topath[MAXPATH]:STRING, -> destinationpath
doinfo, -> should we write informations ?
recursiv, -> scan recursively through subdirectories ?
ignoreprotection, -> clear delete-protection ?
checkversion, -> compare version-strings ?
executestri[MAXPATH]:STRING, -> used with SystemTagList()
dirlock=NIL -> ptr to lock-strcuture of destination path
PROC main() HANDLE
->// "main()"
DEF rdargs=NIL,
myargs:PTR TO LONG,
template
/* Initialize argument-array */
myargs:=[NIL,
NIL,
FALSE,
FALSE,
FALSE,
FALSE]:LONG
/* Parse Commandline */
IF rdargs:=ReadArgs(template:='FROM/M,TO/A,QUIET/S,ALL/S,FORCE/S,DEEP/S',myargs,NIL)
/* Copy Datas to global variables */
fromlist := myargs[0]
StrCopy(topath,myargs[1],ALL)
doinfo := Not(myargs[2])
recursiv := myargs[3]
ignoreprotection := myargs[4]
checkversion := myargs[5]
IF fromlist=NIL THEN Throw("ARGS",'No source specified.')
init_arguments()
IF doinfo THEN PrintF('Updating files to "\s".\n',topath)
WHILE fromlist[] -> 'fromlist' is array of string-pointers
StrCopy(frompath,fromlist[]++,ALL) -> copy the string and increment 'fromlist'
scan_directory(frompath,'',1) -> then process this directory
ENDWHILE
ELSE -> there were errors in commandline, show some info
PrintF(' UpdateCopy v0.40\n'+
' -----------------\n'+
' Copy files and directories.\n'+
' Not existing directories are created and\n'+
' already existing files are only replaced\n'+
' by newer ones. Allows pattern-matching and\n'+
' multiple sourcedirectories/files.\n\n'+
'Sven Steiniger, 1996\n\n')
PrintF('Template: \s\n',template)
PrintF(' FROM - source directory/file(s)\n'+
' TO - destination directory\n'+
' QUIET - no outputs\n'+
' ALL - scans through subdirectories recursively\n'+
' FORCE - ignore protectionbits\n'+
' DEEP - compare version-strings\n')
ENDIF
EXCEPT DO -> Cleanup
free_arguments()
IF rdargs THEN FreeArgs(rdargs)
IF exception
/* Print error description */
PrintF('Error: ')
SELECT exception
CASE "MEM" ; PrintF('Not enough memory.\n')
CASE "ADDP" ; PrintF('Path too long !?\n')
CASE "CTRL" ; PrintF('User abort.\n')
CASE "COPY" ; PrintF('Could not copy file.\n')
CASE "OPEN" ; PrintF('Could not open file.\n')
CASE "ANLY" ; PrintF('Could not analyse file.\n')
DEFAULT ; PrintF('\s\n',exceptioninfo)
ENDSELECT
ENDIF
CleanUp(exception)
ENDPROC
->\\
versionstring: CHAR '$VER: UpdateCopy 0.40 (14.04.96)',0
/* checks the arguments provied by user
*/
PROC init_arguments()
->// "init_arguments()"
IF (dirlock:=Lock(topath,SHARED_LOCK))=NIL -> check if destination
Throw("DIR",'Could not lock destination directory') -> directory exists
ENDIF
ENDPROC
->\\
/* Cleanup datas allocated during init_arguments
*/
PROC free_arguments()
->// "free_arguments()"
UnLock(dirlock) -> Unlock destination directory
ENDPROC
->\\
/* Scans a directory and copies files/creates subdirectories
** Parameter:
** directory - name of directory to be scanned
** path - the current delta path
** depth - recursion level
** Example:
** The source path is "esource:src".
** 'directory' is "esource:src/tools/file".
** Then 'path' have to be "tools/file".
*/
PROC scan_directory(directory,path,depth) HANDLE
->// "scan_directory()"
DEF info:PTR TO fileinfoblock,
anchor=NIL:PTR TO anchorpath,
error,
fullpath,
mypath[MAXPATH]:STRING,
length
/* Create and initialize anchor structure needed for
** scanning through directory.
** This structure has no fixed size.
*/
anchor:=NewR(SIZEOF anchorpath+MAXPATH)
anchor.strlen:=PATHLENGTH
-> Get start of string
fullpath:=anchor+SIZEOF anchorpath
error:=MatchFirst(directory,anchor)
WHILE error=DOSFALSE
CtrlC()
info:=anchor.info -> get fileinfoblock
IF info.direntrytype>0 -> is it a directory ?
StrCopy(mypath,path,ALL) -> init new delta path
AddPart(mypath,info.filename,PATHLENGTH) -> including new subdirectory
printspaces(depth*SPACEADD) -> looks better
process_directory(fullpath,info,mypath) -> knows what to do with this
-> directory
IF recursiv -> scan subdirectories ?
length:=StrLen(fullpath)
IF (length+5)<MAXPATH
CopyMem('/#?',fullpath+length,4) -> add pattern matching
ENDIF
scan_directory(fullpath,mypath,depth+1) -> call our self with new subdirectory
fullpath[length]:=0 -> remove pattern matching
ENDIF
ELSE
printspaces(depth*SPACEADD) -> indent line
process_file(fullpath,info,path) -> knows what to do with it
ENDIF
error:=MatchNext(anchor) -> Next entry
ENDWHILE
EXCEPT DO
IF anchor
MatchEnd(anchor) -> Clean up
Dispose(anchor)
ENDIF
ReThrow()
ENDPROC
->\\
/* Process an directory. If it doesnt exists it will be created
** Parameter:
** directory - full path of source directory
** info - pointer to fileinfoblock of source directory
** path - delta path of directory
*/
PROC process_directory(directory,info:PTR TO fileinfoblock,path)
->// "process_directory()"
DEF stri[MAXPATH]:STRING,
lock
StrCopy(stri,topath,ALL)
AddPart(stri,path,PATHLENGTH) -> thats the destion-directory
IF doinfo THEN PrintF('\e[1m\s\e[0m..',path) -> Write directory name
IF lock:=CreateDir(stri) -> Create the directory
IF doinfo THEN PrintF('created.\n')
UnLock(lock) -> No erros, unlock directory
ELSE -> Directory could not be created
IF IoErr()=ERROR_OBJECT_EXISTS -> Either it already exists
IF doinfo THEN PrintF('skipped.\n')
ELSE
IF doinfo THEN PrintF('\n')
Throw("DIR",'Could not create directory') -> or so something went wrong
ENDIF
ENDIF
ENDPROC
->\\
/* Processes an file. If it does not exists or is newer we copy it.
** Parameter:
** file - full source filename (include path)
** info - ptr to fileinfoblock of sourcefile
** path - deltapath to directory (exclude filename !)
*/
PROC process_file(file,info:PTR TO fileinfoblock,path) HANDLE
->// "process_file()"
DEF stri[MAXPATH]:STRING,
filepath[MAXPATH]:STRING,
fh=NIL,
toinfo=NIL:PTR TO fileinfoblock,
result=0,
frombuf=NIL
StrCopy(filepath,path,ALL) -> create deltapath
AddPart(filepath,info.filename,PATHLENGTH) -> inclusive filename
StrCopy(stri,topath,ALL) -> create full destination
AddPart(stri,filepath,PATHLENGTH) -> filepath
IF doinfo THEN PrintF('\s..',filepath) -> Write filename
IF fh:=Open(stri,MODE_OLDFILE) -> Open destinationfile
/* Fileinfoblock have to be LONGWORD-aligned therefore
** use dos.library to create this
*/
toinfo:=AllocDosObject(DOS_FIB,NIL)
IF ExamineFH(fh,toinfo)<>DOSFALSE -> fill fileinfoblock
IF checkversion THEN result,frombuf:=compareversion(file,stri)
IF result=0
/* Compare versionstrings was either not specified by user
** or was not successfull. Therefore Compare filedates
*/
result:=CompareDates(toinfo.datestamp,info.datestamp)
ENDIF
IF result>0 -> fromfile newer than tofile ?
Close(fh) ; fh:=NIL -> close destination
IF ignoreprotection THEN SetProtection(stri,0) -> Clear protectionflags
-> if specified
copyfile(file,stri,frombuf) -> copy the file
IF doinfo THEN PrintF('replaced.\n')
ELSE
IF doinfo THEN PrintF('skipped.\n')
ENDIF
/* compareversion() may returns us the contents of the
** sourcefile. We must free this buffer
*/
IF frombuf THEN Dispose(frombuf)
ELSE
Throw("FILE",'Could not examine file ?!')
ENDIF
ELSE -> destination does not exists
copyfile(file,stri) -> copy file
IF doinfo THEN PrintF('copied.\n')
ENDIF
EXCEPT DO -> Cleanup
IF toinfo THEN FreeDosObject(DOS_FIB,toinfo)
IF fh THEN Close(fh)
ReThrow()
ENDPROC
->\\
/* Prints 'spaceanz' spaces
*/
PROC printspaces(spaceanz)
->// "printspaces()"
IF doinfo
WHILE spaceanz-- >=0 DO PrintF(' ')
ENDIF
ENDPROC
->\\
/* Copies a file. For files >BIGFILESIZE Bytes c:copy is
** used.
** Parameter:
** fromfile - full path of sourcefile
** tofile - full path of destinationfile
** frombuf - Contents of sourcefile. If NIL then sourcefile
** is read
*/
PROC copyfile(fromfile,tofile,frombuf=NIL) HANDLE
->// "copyfile()"
DEF fhfrom=NIL,
fhto=NIL,
length,
buf=NIL,
info=NIL:PTR TO fileinfoblock
IF (length:=FileLength(fromfile))>BIGFILESIZE
/* Because unbuffered FileIO is used and the whole file is copied
** to memory 'c:copy' should be more optimal for large files.
*/
StringF(executestri,'c:Copy "\s" "\s" QUIET COM NOREQ',fromfile,tofile)
IF SystemTagList(executestri,NIL)<>DOSFALSE THEN Raise("COPY")
ELSE
/* Fileinfoblock have to be LONGWORD-aligned therefore
** use dos.library to create this
*/
info:=AllocDosObject(DOS_FIB,NIL)
IF (fhfrom:=Open(fromfile,OLDFILE)) AND -> open sourcefile
(fhto:=Open(tofile,NEWFILE)) AND -> open destinationfile
(ExamineFH(fhfrom,info)<>DOSFALSE) -> get sourcefile-data
IF frombuf -> we already know the
-> contents of the sourcefile
/* Write buffer to destinationfile */
IF Write(fhto,frombuf,length)<>length THEN Raise("COPY")
ELSE
buf:=NewR(length) -> alloc new buffer
/* Read sourcefile into buffer */
IF Read(fhfrom,buf,length)<>length THEN Raise("COPY")
/* Write buffer TO destinationfile */
IF Write(fhto,buf,length)<>length THEN Raise("COPY")
ENDIF
SetProtection(tofile,info.protection) -> Copy protection bits
SetComment(tofile,info.comment) -> Copy comment
ELSE -> There went something wrong
Raise("COPY")
ENDIF
ENDIF
EXCEPT DO -> Cleanup
IF info THEN FreeDosObject(DOS_FIB,info)
IF buf THEN Dispose(buf)
IF fhfrom THEN Close(fhfrom)
IF fhto THEN Close(fhto)
ReThrow()
ENDPROC
->\\
/* Compares the version-strings of two files
** Parameter:
** fromfile - full path of sourcefile
** tofile - full path of destinationfile
**
** Returns
** -1 if tofile-version>fromfile-version
** 0 if =
** 1 if <
** *AND* the contents of the sourcefile or NIL
*/
PROC compareversion(fromfile,tofile) HANDLE
->// "compareversion()"
DEF buffer=NIL:PTR TO CHAR,
version1,base1,
version2,base2
version2,base2,buffer:=getVersionOfFile(tofile)
/* We dont need the destination contents. Therefore delete buffer
*/
IF buffer
Dispose(buffer)
buffer:=NIL
ENDIF
/* if version is -1 then no version-string was found */
IF version2=-1 THEN RETURN 0,NIL
version1,base1,buffer:=getVersionOfFile(fromfile)
IF version1=-1 THEN RETURN 0,buffer
/* Compare the version, reversion of source/destionation
** multiply with other base to get same number of signifant numbers
*/
IF (version2*base1)>=(version1*base2)
RETURN -1,buffer
ELSE
RETURN 1,buffer
ENDIF
EXCEPT -> Cleanup
IF buffer THEN Dispose(buffer)
ReThrow()
ENDPROC
->\\
/* Gets the version-number of a file
** Parameter:
** filename - full path of file
** Returns the version, base and a buffer with the contents of the file
** (description for version,base see getversion())
** buffer may be NIL if file was to large
*/
PROC getVersionOfFile(filename) HANDLE
->// "getVersionOfFile()"
DEF fh=NIL,
buffer=NIL:PTR TO CHAR,
version,base,
steplength,filelength,actlength
IF fh:=Open(filename,OLDFILE)
filelength:=FileLength(filename)
IF filelength>BIGFILESIZE
/* Files >BIGFILESIZE are not read completly into memory but in parts
** of BIGFILESIZE Bytes.
** As we may skip a versionstring the last SAFETYBYTES are copied
** to start of new BIGFILESIZE block everytime.
*/
/* Alloc new buffer and read filecontents into it */
buffer:=NewR(BIGFILEMEM)
IF Read(fh,buffer,BIGFILEMEM)<>BIGFILEMEM THEN Raise("ANLY")
/* steplength is he length of the current block to be read */
steplength:=BIGFILESIZE
/* actlength is the position within the file */
actlength:=BIGFILEMEM
REPEAT
/* Get version. If version=-1 then read next block */
version,base:=getversion(buffer,steplength+SAFETYBYTES)
IF version=-1
/* The version-string was maybe at the end of buffer
** and therfore skipped. Copy the last SAFETYBYTES bytes
** to start of buffer to not lose the version-string.
*/
CopyMem(buffer+steplength,buffer,SAFETYBYTES)
/* Increase actlength. If actlength is greater than filelength
** then set steplength to the number of bytes left.
*/
actlength:=actlength+BIGFILESIZE
IF actlength>filelength
steplength:=filelength-(actlength-BIGFILESIZE)
ENDIF
/* Read next block to buffer. If steplength<0 then EOF is reached */
IF steplength>0
IF Read(fh,buffer+SAFETYBYTES,steplength)<>steplength THEN Raise("ANLY")
ENDIF
ENDIF
/* Read until version-string was found or EOF */
UNTIL (version<>-1) OR (steplength<=0)
Dispose(buffer)
buffer:=NIL
ELSE
/* We have got a small file. Load it completly into memory.
** Alloc new buffer and read filecontents into it
*/
buffer:=NewR(filelength)
IF Read(fh,buffer,filelength)<>filelength THEN Raise("ANLY")
/* get versions and reversion of sourcefile */
version,base:=getversion(buffer,filelength)
ENDIF
/* We dont need the filehandle any longer */
Close(fh)
fh:=NIL
ELSE
Raise("OPEN")
ENDIF
EXCEPT
IF fh THEN Close(fh)
IF buffer THEN Dispose(buffer)
ReThrow()
ENDPROC version,base,buffer
->\\
/* Search for a version-string in a file
** Parameter:
** buffer - Contents of file
** bufferlength - length of buffer in bytes
** Retuns version,base
** if no version-string was found then -1 is returned as version
** Example: version=81259, base=10000 means
** Versionnumber is 81259/10000=8.1259
*/
PROC getversion(buffer:PTR TO CHAR,bufferlength)
->// "getversion()"
DEF version=-1:REG,base:REG
MOVEA.L buffer,A0 -> A0..buffer
MOVE.L bufferlength,D0 -> D0..bufferlength
SUBQ.L #1,D0
MOVE.B #"$",D1
MOVE.L #"VER:",D2
gv_search_loop:
SUBQ.L #1,D0
BLT.W gv_ende -> bufferend reached ?
CMP.B (A0)+,D1
BNE.S gv_search_loop -> Found a "$" ?
CMP.L (A0),D2 -> Yes, then next characters="VER:"
BNE.S gv_search_loop
SUBQ.L #4,D0 -> We have found a version-string
BLT.S gv_ende
ADDQ.L #4,A0 -> skip "VER:"
MOVE.B #" ",D1
gv_skipspaces1: -> skip all spaces before programname
SUBQ.L #1,D0
BLT.S gv_ende -> bufferend reached ?
CMP.B (A0)+,D1
BEQ.S gv_skipspaces1
ADDQ.L #1,D0 -> all spaces skipped; we have gone
SUBQ.L #1,A0 -> one step too far.
gv_skipname: -> skip programname
SUBQ.L #1,D0
BLT.S gv_ende -> bufferend reached ?
CMP.B (A0)+,D1
BNE.S gv_skipname
ADDQ.L #1,D0 -> go one step back
SUBQ.L #1,A0
gv_skipspaces2: -> skip spaces before version-number
SUBQ.L #1,D0
BLT.S gv_ende -> bufferend reached ?
CMP.B (A0)+,D1
BEQ.S gv_skipspaces2
ADDQ.L #1,D0 -> go one step back
SUBQ.L #1,A0
MOVEQ #0,version
MOVE.B #".",D1
MOVEQ #0,D2
gv_getversion1: -> get version until we found a "."
SUBQ.L #1,D0
BLT.S gv_ende -> bufferend reached ?
MOVE.B (A0)+,D2
SUBI.L #"0",D2 -> Transform character "0".."9" into number
MULU.W #10,version -> version:=version*10
ADD.L D2,version -> +number
CMP.B (A0),D1
BNE.S gv_getversion1
SUBQ.L #1,D0 -> skip "."
ADDQ.L #1,A0
MOVE.B #" ",D1
MOVEQ #1,base
gv_getversion2: -> get reversion
SUBQ.L #1,D0
BLT.S gv_ende -> bufferend reached ?
MOVE.B (A0)+,D2
SUBI.L #"0",D2 -> Transform character "0".."9" into number
MULU.W #10,version -> version:=version*10
MULU.W #10,base -> base:=base*10
ADD.L D2,version -> +number
CMP.B (A0),D1
BNE.S gv_getversion2
gv_ende:
ENDPROC version,base
->\\